package com.atguigu.springcloud.cloudsentinelgatewaydevelop.service;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingMaintainService;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.atguigu.springcloud.cloudsentinelgatewaydevelop.bean.dto.vo.ServiceView;
import com.atguigu.springcloud.cloudsentinelgatewaydevelop.bean.dto.vo.InstanceVO;
import com.atguigu.springcloud.cloudsentinelgatewaydevelop.nacos.NacosManagerUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Scheduler;
import reactor.core.scheduler.Schedulers;

import java.util.ArrayList;
import java.util.List;

@Slf4j
@Service
public class NacosManagerService {
    Scheduler naocsSchedule = Schedulers.newParallel("NaocsSchedule", 200);
    @Autowired
    NamingMaintainService namingMaintainService;
    @Autowired
    RestTemplate restTemplate;
    @Autowired
    NamingService namingService;
    @Autowired
    DiscoveryClient discoveryClient;
    @Autowired
    ConfigService configService;
    @Autowired
    NacosManagerUtil nacosManagerUtil;

    public Mono<List<ServiceView>> getAllServiceInstance(int pageNo, int pageSize) throws NacosException {

        Mono<List<ServiceView>> serviceViews =
                Mono.fromCallable(() -> {
                    return namingService.getServicesOfServer(pageNo, pageSize).getData();
                })
        .log().publishOn(naocsSchedule).map(names -> {
            List<ServiceView> ret = new ArrayList<>();
            for (String serviceName : names) {
                ServiceView serviceView = new ServiceView();
                serviceView.setServiceName(serviceName);
                JSONObject serviceDetail = null;
                try {
                    serviceDetail = nacosManagerUtil.doGetServiceDetail(serviceName).getBody();
                    serviceView.setProtectThreshold(serviceDetail.getFloat("protectThreshold"));
                    serviceView.setSelector(serviceDetail.getString("selector"));
                } catch (Exception e) {
                    e.printStackTrace();
                }

                List<Instance> allInstances = new ArrayList<>();
                try {
                    allInstances.addAll(namingService.getAllInstances(serviceName));
                } catch (NacosException e) {
                    e.printStackTrace();
                }
                serviceView.setInstances(allInstances);
                serviceView.setAllInstanceCount(allInstances.size());
                Integer helthInstanceNum = 0;
                for (Instance instance : allInstances) {
                    if (instance.isHealthy()) {
                        helthInstanceNum++;
                    }
                }
                serviceView.setHelthyInstanceNum(helthInstanceNum);
                ret.add(serviceView);
            }
            return ret;
        }).log();

        return serviceViews;
    }

    public List<String> test() throws NacosException {
        try {
            Thread.sleep(100000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return namingService.getServicesOfServer(1, 10).getData();
    }

    public Mono<Integer> getServiceCount() {
        return Mono.fromCallable(()->discoveryClient.getServices().size()).publishOn(naocsSchedule).log();
    }

    public Mono<ResponseEntity<String>> createService(String serviceName, String protectThreshold, String metadata, String selector) throws NacosException {
        return Mono.fromCallable(()->nacosManagerUtil.doCreateService(serviceName, protectThreshold, metadata, selector)).publishOn(naocsSchedule).log();
    }

    public Mono<ResponseEntity<String>> deRegisterService(String serviceName) {
        return Mono.fromCallable(()->nacosManagerUtil.deRegisterService(serviceName)).publishOn(naocsSchedule).log();
    }

    public Mono<ResponseEntity<String>> deRegisterInstance(String serviceName, String ip, int port, Boolean ephemeral) {

        return Mono.fromCallable(()->nacosManagerUtil.doDeRegisterInstance(serviceName, ip, port, ephemeral)).publishOn(naocsSchedule).log();
    }

    public Mono<ResponseEntity<String>> updateService(String serviceName, String protectThreshold, String metadata, String selector) {
        return Mono.fromCallable(() -> nacosManagerUtil.doUpDateService(serviceName, protectThreshold, metadata, selector)).publishOn(naocsSchedule).log();
    }

    public Mono<ResponseEntity<JSONObject>> getAllConfig(int pageNo, int pageSize) {
         return Mono.fromCallable(
                 () -> nacosManagerUtil.doGetAllConfig(pageNo, pageSize)
         ).log().publishOn(naocsSchedule);
    }

    public Mono<Boolean> addOrUpdateConfig(String dataId, String content, String type) {
                return Mono.fromCallable(
                        ()->configService.publishConfig(dataId, nacosManagerUtil.getNacosConfigPorperties().getGroup(), content, type)
                ).publishOn(naocsSchedule);

    }

    public Mono<Boolean> deleteConfig(String dataId) {
                return Mono.fromCallable(
                        ()->configService.removeConfig(dataId, nacosManagerUtil.getNacosConfigPorperties().getGroup())
                ).publishOn(naocsSchedule);

    }

    public Mono<ResponseEntity<String>> updateInstance(InstanceVO instance) {
        return Mono.fromCallable(()->nacosManagerUtil.doUpDateInstance(instance)).publishOn(naocsSchedule);
    }
}
